﻿#include "videodevice.h"

Q_DECLARE_METATYPE(QCameraInfo)

VideoDevice::VideoDevice(QSize showSize, QWidget *parent) :
    QWidget(parent)
{
    m_frameData = new QByteArray();

    m_cameraTimer = new QTimer(this);
    QObject::connect(m_cameraTimer, &QTimer::timeout, this, &VideoDevice::cameraTimeoutSlot);

    m_viewFinder = new QCameraViewfinder(parent);
    m_viewFinder->setWindowFlag(Qt::FramelessWindowHint);
    m_viewFinder->setFixedSize(showSize.width(), showSize.height());

    setCamera(QCameraInfo::defaultCamera());
}

VideoDevice::~VideoDevice()
{
    closeCamera();
    m_frameData->clear();
    delete m_frameData;

    delete m_videoProbe;
    delete m_camera;
}

void VideoDevice::setCamera(const QCameraInfo &cameraInfo)
{
    //初始化摄像头
    m_camera = new QCamera(cameraInfo, this);
    connect(m_camera, &QCamera::stateChanged, this, &VideoDevice::updateCameraState);
    connect(m_camera, QOverload<QCamera::Error>::of(&QCamera::error), this, &VideoDevice::showCameraError);

    updateCameraState(m_camera->state());

    /*
     * QVideoFrame::Format_YUV420P
     * YYYYYY
     * YYYYYY
     * YYYYYY
     * UUUUUU
     * VVVVVV
     */
    QCameraViewfinderSettings settings;
    settings.setPixelFormat(QVideoFrame::Format_YUV420P);
    settings.setMinimumFrameRate(VIDEO_FPS);
    settings.setMaximumFrameRate(VIDEO_FPS);
    settings.setResolution(QSize(CAMERA_PIXEL_WIDE, CAMERA_PIXEL_HIGH));
    m_camera->setViewfinderSettings(settings);

    m_videoProbe = new QVideoProbe(this);
    m_videoProbe->setSource(m_camera);
    connect(m_videoProbe, &QVideoProbe::videoFrameProbed, this, &VideoDevice::onProbeFrameSlot);
}

void VideoDevice::openCamera(bool reboot)
{
    if (isCameraOpen && !reboot)
        return ;

    m_camera->stop();
    m_camera->unload();
    m_camera->setCaptureMode(QCamera::CaptureVideo);
    m_camera->start();
    isCameraOpen = true;
    if (!m_cameraTimer->isActive())
        m_cameraTimer->start(10);
}

void VideoDevice::closeCamera()
{
    isCameraOpen = false;
    m_camera->stop();
    m_camera->unload();
    m_cameraTimer->stop();
}

void VideoDevice::showViewfinder(int x, int y)
{
    if (m_viewFinder == nullptr)
        return ;
    m_camera->setViewfinder(m_viewFinder);
    m_viewFinder->move(x, y);
    m_viewFinder->show();
}

void VideoDevice::updateCameraState(QCamera::State state)
{
    switch (state)
    {
    case QCamera::ActiveState: break;
    case QCamera::UnloadedState:
    case QCamera::LoadedState: break;
    }
}

void VideoDevice::showCameraError(void)
{
    qDebug()<<"Camera error:"<<m_camera->errorString();
}

void VideoDevice::getFrameData(void * pData)
{
    QReadLocker readLock(&m_frameRWLock);
    memcpy(pData, m_frameData->data(), m_frameData->length());
}

void VideoDevice::getFrameData(QByteArray &pArray)
{
    QReadLocker readLock(&m_frameRWLock);
    pArray.append(*m_frameData);
}

void VideoDevice::onProbeFrameSlot(const QVideoFrame &frame)
{
    m_cameraCnt = 0;

    if (!m_probeStatus)
        return ;

    QVideoFrame cloneFrame(frame);

    if (!cloneFrame.map(QAbstractVideoBuffer::ReadOnly)) {
        return ;
    }

    {
        QWriteLocker writeLock(&m_frameRWLock);
        m_frameData->clear();
        m_frameData->append((const char *)cloneFrame.bits(), cloneFrame.mappedBytes());
    }
    cloneFrame.unmap();

    emit videoFrameSingal();
}

void VideoDevice::cameraTimeoutSlot()
{
    m_cameraCnt++;
    //800ms
    if (m_cameraCnt > 80)
    {
        qDebug()<<"camera is timeout!";
        m_cameraCnt = 0;
        openCamera(true);
    }
}
